package com.niiwoo.civet.trade.service.local.plan;

import com.niiwoo.civet.base.enums.FeeTypeEnum;
import com.niiwoo.civet.trade.constant.AmountHandleConstant;
import com.niiwoo.civet.trade.constant.DatePatternConstant;
import com.niiwoo.civet.trade.dao.entity.*;
import com.niiwoo.civet.trade.dao.mapper.*;
import com.niiwoo.civet.trade.dto.BorrowerRepaymentDTO;
import com.niiwoo.civet.trade.dto.RateConfigDTO;
import com.niiwoo.civet.trade.dto.common.BuildRepaymentDTO;
import com.niiwoo.civet.trade.dto.request.loan.RepaymentPlanDTO;
import com.niiwoo.civet.trade.enums.*;
import com.niiwoo.civet.trade.service.local.intelligenceInvest.ProjectPackageLocalService;
import com.niiwoo.tripod.consumer.helper.Exceptions;
import com.niiwoo.tripod.service.component.SnowflakeIdWorker;

import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.MathContext;
import java.util.*;

/**
 * 等额本息
 *
 * @author liaojunjun
 *
 */
@Service
public class AverageCapitalPlusInterest extends AbstractBorrowerInvestorRepaymentManager {

	@Autowired
	private SnowflakeIdWorker snowflakeIdWorker;

	@Autowired
	private ProjectBorrowerSummaryMapper projectBorrowerSummaryMapper;

	@Autowired
	private ProjectBorrowerPlanNewMapper projectBorrowerPlanNewMapper;

	@Autowired
	private ProjectBorrowerPlanDetailMapperExt projectBorrowerPlanDetailMapperExt;

	@Autowired
	private ProjectInvestorPlanMapper projectInvestorPlanMapper;

	@Autowired
	private InvestorCreditorMapperExt investorCreditorMapperExt;

	@Autowired
	private ProjectPackageLocalService projectPackageLocalService;

	@Override
	public boolean supports(InterestAccrualEnum interestAccrualEnum) {
		return InterestAccrualEnum.AVERAGE_CAPITAL_PLUS_INTEREST.equals(interestAccrualEnum);
	}

	@Override
	public List<RepaymentPlanDTO> getBorrowerRepaymentPlan(BigDecimal amount, BigDecimal yearRate, Integer deadline,
			PeriodUnitEnum periodUnitEnum, Date startDate, Integer leastCalculateInterestDays) {
		if (PeriodUnitEnum.MONTH != periodUnitEnum) {
			Exceptions.throwBizException("TRD_700003");// 等额本息还款方式的期限单位不是月
		}
		List<RepaymentPlanDTO> result = new ArrayList<RepaymentPlanDTO>();
		// 月利率： 年化利率/12
		BigDecimal monthRate = yearRate.divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_MONTH),
				MathContext.DECIMAL128);

		BigDecimal monthIncome = getPerMonthPrincipalInterest(amount, monthRate, deadline);
		Map<Integer, BigDecimal> capitalMap = getPerMonthCapital(amount, monthRate, deadline);
		Map<Integer, BigDecimal> interestMap = getPerMonthInterest(amount, monthRate, deadline);
		
		BigDecimal capitalTotal = BigDecimal.ZERO;

		for (int i = 1; i < deadline + 1; i++) {
			RepaymentPlanDTO repaymentPlanDTO = new RepaymentPlanDTO();
			repaymentPlanDTO.setPlanType(RepaymentTypeEnum.AVERAGE_CAPITAL_PLUS_INTEREST.getValue());
			repaymentPlanDTO.setCurrentPeriod(i);
			repaymentPlanDTO.setTotalPeriod(deadline);
			repaymentPlanDTO.setPrincipal(capitalMap.get(i));
			repaymentPlanDTO.setInterest(interestMap.get(i));
			repaymentPlanDTO.setPrincipalInterest(monthIncome);
			repaymentPlanDTO.setRefundDate(DateUtils.addDays(DateUtils.addMonths(startDate, i), -1));
			
			capitalTotal = capitalTotal.add(repaymentPlanDTO.getPrincipal());
			
			// 应还款本金不等于实际还款金额时 最后一期做本金抹平处理
			if (i == deadline) {
				repaymentPlanDTO.setPrincipalInterest(getLastPerMonthPrincipalInterest(amount, monthRate, deadline));
				
				if (amount.compareTo(capitalTotal) != 0) {
					repaymentPlanDTO.setPrincipal(capitalMap.get(i).add(amount.subtract(capitalTotal)));
					repaymentPlanDTO.setInterest(interestMap.get(i).subtract(amount.subtract(capitalTotal)));
				}
				
				if(repaymentPlanDTO.getInterest().compareTo(BigDecimal.ZERO) < 0){
					repaymentPlanDTO.setInterest(BigDecimal.ZERO);
					repaymentPlanDTO.setPrincipalInterest(repaymentPlanDTO.getPrincipal());
				}
			} 
			
			result.add(repaymentPlanDTO);
		}

		return result;
	}

	@Override
	public List<RepaymentPlanDTO> getBorrowerRepaymentPlan(BuildRepaymentDTO buildRepaymentDTO, List<RateConfigDTO> rateConfigDTOList) {
		List<RepaymentPlanDTO> result = new ArrayList<RepaymentPlanDTO>();
		PeriodUnitEnum periodUnit = buildRepaymentDTO.getPeriodUnit();
		if (PeriodUnitEnum.MONTH != periodUnit) {
			Exceptions.throwBizException("TRD_700003");// 等额本息还款方式的期限单位不是月
		}

		// 月利率： 年化利率/12
		BigDecimal monthRate = buildRepaymentDTO.getYearRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_MONTH),
				MathContext.DECIMAL128);

		// 担保服务费
		BigDecimal guaranteeServiceFeeTotal = buildRepaymentDTO.getAmount().multiply(buildRepaymentDTO.getGuaranteeRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
		BigDecimal guaranteeServiceFee = BigDecimal.ZERO;

		// 平台管理费
		BigDecimal platformManageFeeTotal = buildRepaymentDTO.getAmount().multiply(buildRepaymentDTO.getManageRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
		BigDecimal platformManageFee = BigDecimal.ZERO;

        // lastAvailableGuaranteeServiceFee 最后一期有效担保服务费
        Integer lastAvailableGuaranteeServiceFee = rateConfigDTOList.size();
        // lastAvailablePlatformManageFee 最后一期有效平台管理费
        Integer lastAvailablePlatformManageFee = rateConfigDTOList.size();
        for(int i = rateConfigDTOList.size() - 1 ; i >= 0; i--){
            if(rateConfigDTOList.get(i).getGuaranteeServiceFeePercent().compareTo(BigDecimal.ZERO) > 0){
                lastAvailableGuaranteeServiceFee = rateConfigDTOList.get(i).getCurrentPeriod();
                break;
            }
        }
        for(int i = rateConfigDTOList.size() - 1 ; i >= 0; i--){
            if(rateConfigDTOList.get(i).getPlatformManageFeePercent().compareTo(BigDecimal.ZERO) > 0){
                lastAvailablePlatformManageFee = rateConfigDTOList.get(i).getCurrentPeriod();
                break;
            }
        }

		BigDecimal monthIncome = getPerMonthPrincipalInterest(buildRepaymentDTO.getAmount(), monthRate,
				buildRepaymentDTO.getDeadline());
		Map<Integer, BigDecimal> capitalMap = getPerMonthCapital(buildRepaymentDTO.getAmount(), monthRate,
				buildRepaymentDTO.getDeadline());
		Map<Integer, BigDecimal> interestMap = getPerMonthInterest(buildRepaymentDTO.getAmount(), monthRate,
				buildRepaymentDTO.getDeadline());
		
		BigDecimal capitalTotal = BigDecimal.ZERO;

		for (int i = 1; i < buildRepaymentDTO.getDeadline() + 1; i++) {
			RepaymentPlanDTO repaymentPlanDTO = new RepaymentPlanDTO();
			repaymentPlanDTO.setPlanType(RepaymentTypeEnum.AVERAGE_CAPITAL_PLUS_INTEREST.getValue());
			repaymentPlanDTO.setCurrentPeriod(i);
			repaymentPlanDTO.setTotalPeriod(buildRepaymentDTO.getDeadline());
			repaymentPlanDTO.setPrincipal(capitalMap.get(i));
			repaymentPlanDTO.setInterest(interestMap.get(i));
			repaymentPlanDTO.setPrincipalInterest(monthIncome);
			repaymentPlanDTO.setRefundDate(DateUtils.addDays(
					DateUtils.addMonths(
							buildRepaymentDTO.getStartDate() == null ? new Date() : buildRepaymentDTO.getStartDate(), i), -1));

			repaymentPlanDTO.setGuaranteeServiceFee(BigDecimal.ZERO);
			repaymentPlanDTO.setPlatformManageFee(BigDecimal.ZERO);

            for (RateConfigDTO rateConfigDTO : rateConfigDTOList) {
                if (rateConfigDTO != null && rateConfigDTO.getCurrentPeriod() == i) {
                    // 抹平管理费
                    // lastAvailablePlatformManageFee 为最后一期有效平台管理费 最后一期有效平台管理费=收费用总收费减去前N期收费之和
                    if (rateConfigDTO.getCurrentPeriod().equals(lastAvailablePlatformManageFee)) {
                        repaymentPlanDTO.setPlatformManageFee(platformManageFeeTotal.subtract(platformManageFee));
                    } else {
                        repaymentPlanDTO.setPlatformManageFee(platformManageFeeTotal.multiply(
                                rateConfigDTO.getPlatformManageFeePercent()).setScale(
                                AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));

                        platformManageFee = platformManageFee.add(repaymentPlanDTO.getPlatformManageFee());
                    }

                    // 抹平担保服务费
                    // lastAvailableGuaranteeServiceFee 为最后一期有效担保服务费 最后一次有效担保服务费=收费用总收费减去前N期收费之和
                    if (rateConfigDTO.getCurrentPeriod().equals(lastAvailableGuaranteeServiceFee)) {
                        repaymentPlanDTO.setGuaranteeServiceFee(guaranteeServiceFeeTotal.subtract(guaranteeServiceFee));
                    } else {
                        repaymentPlanDTO.setGuaranteeServiceFee(guaranteeServiceFeeTotal.multiply(
                                rateConfigDTO.getGuaranteeServiceFeePercent()).setScale(
                                AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN));

                        guaranteeServiceFee = guaranteeServiceFee.add(repaymentPlanDTO.getGuaranteeServiceFee());
                    }
                    break;
                }
            }
			
			capitalTotal = capitalTotal.add(repaymentPlanDTO.getPrincipal());
			
			// 应还款本金不等于实际还款金额时 最后一期做本金抹平处理
			if (i == buildRepaymentDTO.getDeadline()) {
				repaymentPlanDTO.setPrincipalInterest(getLastPerMonthPrincipalInterest(buildRepaymentDTO.getAmount(), monthRate, buildRepaymentDTO.getDeadline()));
				
				if (buildRepaymentDTO.getAmount().compareTo(capitalTotal) != 0) {
					repaymentPlanDTO.setPrincipal(capitalMap.get(i).add(buildRepaymentDTO.getAmount().subtract(capitalTotal)));
					repaymentPlanDTO.setInterest(interestMap.get(i).subtract(buildRepaymentDTO.getAmount().subtract(capitalTotal)));
				}
				
				if(repaymentPlanDTO.getInterest().compareTo(BigDecimal.ZERO) < 0){
					repaymentPlanDTO.setInterest(BigDecimal.ZERO);
					repaymentPlanDTO.setPrincipalInterest(repaymentPlanDTO.getPrincipal());
				}
			} 

			repaymentPlanDTO.setRepaymentTotalAmount(repaymentPlanDTO.getPrincipalInterest()
					.add(repaymentPlanDTO.getGuaranteeServiceFee()).add(repaymentPlanDTO.getPlatformManageFee()));

			result.add(repaymentPlanDTO);
		}

		return result;
	}

	@Override
	public BorrowerRepaymentDTO buildBorrowerRepaymentPlan(Project project,
			ProjectBorrowerSummary projectBorrowerSummary, List<ProjectRate> projectRateList) {
		BorrowerRepaymentDTO result = new BorrowerRepaymentDTO();

		PeriodUnitEnum periodUnit = PeriodUnitEnum.enumOf(project.getDeadlineUnit());
		if (PeriodUnitEnum.MONTH != periodUnit) {
			Exceptions.throwBizException("TRD_700003");// 等额本息还款方式的期限单位不是月
		}

		projectBorrowerSummary.setTotalPeriod(project.getDeadline());
		projectBorrowerSummary.setRefundDate(DateUtils.addDays(DateUtils.addMonths(project.getFullSuccessTime(), 1), -1));
		projectBorrowerSummary.setAutoRefundDate(projectBorrowerSummary.getRefundDate());

		projectBorrowerSummaryMapper.insertSelective(projectBorrowerSummary);

		List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = new ArrayList<>();

		// 月利率： 年化利率/12
		BigDecimal monthRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_MONTH),
				MathContext.DECIMAL128);

		// 担保服务费
		BigDecimal guaranteeServiceFeeTotal = !ProjectFeeChargeNodeEnum.GuaranteeFeeChargeNode.COLLECTION_OF_MONEY.getValue().
				equals(project.getGuaranteeFeeChargeNode()) ? project.getContractAmount().multiply(project.getGuaranteeRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN) : BigDecimal.ZERO;
		BigDecimal guaranteeServiceFee = BigDecimal.ZERO;

		// 平台管理费
		BigDecimal platformManageFeeTotal = !ProjectFeeChargeNodeEnum.ManageFeeChargeNode.COLLECTION_OF_MONEY.getValue().
				equals(project.getManageFeeChargeNode()) ? project.getContractAmount().multiply(project.getManageRate())
				.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN) : BigDecimal.ZERO;
		BigDecimal platformManageFee = BigDecimal.ZERO;

		// 咨询服务费(按照合同金额*费率)
		BigDecimal consultingFeeTotal = !ProjectFeeChargeNodeEnum.AfterSeekAdviceServiceFeeChargeNode.COLLECTION_OF_MONEY.getValue().
				equals(project.getAfterSeekAdviceServiceFeeChargeNode()) ? project.getContractAmount() : BigDecimal.ZERO;

        // lastAvailableGuaranteeServiceFee 最后一期有效担保服务费
        Integer lastAvailableGuaranteeServiceFee = projectRateList.size();
        // lastAvailablePlatformManageFee 最后一期有效平台管理费
        Integer lastAvailablePlatformManageFee = projectRateList.size();
        for(int i = projectRateList.size() - 1 ; i >= 0; i--){
            if(projectRateList.get(i).getGuaranteeServiceFeePercent().compareTo(BigDecimal.ZERO) > 0){
                lastAvailableGuaranteeServiceFee = projectRateList.get(i).getCurrentPeriod();
                break;
            }
        }
        for(int i = projectRateList.size() - 1 ; i >= 0; i--){
            if(projectRateList.get(i).getPlatformManageFeePercent().compareTo(BigDecimal.ZERO) > 0){
                lastAvailablePlatformManageFee = projectRateList.get(i).getCurrentPeriod();
                break;
            }
        }

		Map<Integer, BigDecimal> capitalMap = getPerMonthCapital(project.getContractAmount(), monthRate,
				project.getDeadline());
		Map<Integer, BigDecimal> interestMap = getPerMonthInterest(project.getContractAmount(), monthRate,
				project.getDeadline());
		
		BigDecimal capitalTotal = BigDecimal.ZERO;

		BigDecimal currentGuaranteeServiceFee;
		BigDecimal currentPlatformManageFee;
		BigDecimal currentConsultingFee;
		for (int i = 1; i < project.getDeadline() + 1; i++) {
			Date refundDate = DateUtils.addDays(DateUtils.addMonths(project.getFullSuccessTime(), i), -1);

			ProjectBorrowerPlanNew projectBorrowerPlanNew = buildProjectBorrowerPlanNew(snowflakeIdWorker.nextId(),
					project.getProjectId(), project.getBorrowUserId(), project.getBorrowAccountId(), refundDate, i, periodUnit.getValue(), project.getDeadline());
			projectBorrowerPlanNewMapper.insertSelective(projectBorrowerPlanNew);

            for (ProjectRate projectRate : projectRateList) {
                if (projectRate != null && projectRate.getCurrentPeriod() == i) {
					// 抹平管理费
					// lastAvailablePlatformManageFee 为最后一期有效平台管理费 最后一期有效平台管理费=收费用总收费减去前N期收费之和
					if(ProjectFeeChargeNodeEnum.ManageFeeChargeNode.REPAYMENT_FIRST.getValue().
							equals(project.getManageFeeChargeNode())){
						currentPlatformManageFee = i == 1 ? platformManageFeeTotal : BigDecimal.ZERO;
					}else{
						if (projectRate.getCurrentPeriod().equals(lastAvailablePlatformManageFee)) {
							currentPlatformManageFee = platformManageFeeTotal.subtract(platformManageFee);
						} else {
							currentPlatformManageFee = platformManageFeeTotal.multiply(
									projectRate.getPlatformManageFeePercent()).setScale(
									AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);

							platformManageFee = platformManageFee.add(currentPlatformManageFee);
						}
					}


					// 抹平担保服务费
					// lastAvailableGuaranteeServiceFee 为最后一期有效担保服务费 最后一次有效担保服务费=收费用总收费减去前N期收费之和
					if(ProjectFeeChargeNodeEnum.GuaranteeFeeChargeNode.REPAYMENT_FIRST.getValue().
							equals(project.getGuaranteeFeeChargeNode())){
						currentGuaranteeServiceFee = i == 1 ? guaranteeServiceFeeTotal : BigDecimal.ZERO;
					}else{
						if (projectRate.getCurrentPeriod().equals(lastAvailableGuaranteeServiceFee)) {
							currentGuaranteeServiceFee = guaranteeServiceFeeTotal.subtract(guaranteeServiceFee);
						} else {
							currentGuaranteeServiceFee = guaranteeServiceFeeTotal.multiply(
									projectRate.getGuaranteeServiceFeePercent()).setScale(
									AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);

							guaranteeServiceFee = guaranteeServiceFee.add(currentGuaranteeServiceFee);
						}
					}

					if(ProjectFeeChargeNodeEnum.AfterSeekAdviceServiceFeeChargeNode.REPAYMENT_FIRST.getValue().
							equals(project.getAfterSeekAdviceServiceFeeChargeNode())){
						currentConsultingFee = i == 1 ? project.getConsultingFee() : BigDecimal.ZERO;
					}else{
						currentConsultingFee = consultingFeeTotal.multiply(
								projectRate.getAfterSeekAdviceServiceFeeRate()).setScale(
								AmountHandleConstant.CALCULATE_PRECISION_TWO, BigDecimal.ROUND_HALF_EVEN);
					}

                    if(currentGuaranteeServiceFee.compareTo(BigDecimal.ZERO) != 0) {
                        ProjectBorrowerPlanDetail guaranteeServiceFeeDetail = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
                                project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(),
                                FeeTypeEnum.GUARANTEE_FEE.getValue().intValue(), currentGuaranteeServiceFee);
                        projectBorrowerPlanDetailMapperExt.insertSelective(guaranteeServiceFeeDetail);
                    }

                    if(currentPlatformManageFee.compareTo(BigDecimal.ZERO) != 0) {
                        ProjectBorrowerPlanDetail platformManageFeeDetail = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
                                project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(),
                                FeeTypeEnum.MANAGEMENT_FEE.getValue().intValue(), currentPlatformManageFee);
                        projectBorrowerPlanDetailMapperExt.insertSelective(platformManageFeeDetail);
                    }

                    if(currentConsultingFee.compareTo(BigDecimal.ZERO) != 0){
						ProjectBorrowerPlanDetail consultingFeeDetail = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
								project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(),
								FeeTypeEnum.CONSULTING_FEE.getValue().intValue(), currentConsultingFee);
						projectBorrowerPlanDetailMapperExt.insertSelective(consultingFeeDetail);
					}
                    break;
                }
            }

			BigDecimal currentCapital = capitalMap.get(i);
			BigDecimal currentInterest = interestMap.get(i);
			
			capitalTotal = capitalTotal.add(currentCapital);
			
			// 应还款本金不等于实际还款金额时 最后一期做本金抹平处理
			if (i == project.getDeadline()) {
				if (project.getContractAmount().compareTo(capitalTotal) != 0) {
					currentCapital = capitalMap.get(i).add(project.getContractAmount().subtract(capitalTotal));
					currentInterest = interestMap.get(i).subtract(project.getContractAmount().subtract(capitalTotal));
				}
				
				if(currentInterest.compareTo(BigDecimal.ZERO) < 0){
					currentInterest = BigDecimal.ZERO;
				}
			}

			// 本金
			ProjectBorrowerPlanDetail capitalDetail = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(), project.getProjectId(),
					project.getBorrowUserId(), projectBorrowerPlanNew.getId(), FeeTypeEnum.CAPITAL.getValue().intValue(), currentCapital);
			projectBorrowerPlanDetailMapperExt.insertSelective(capitalDetail);

			// 利息
			ProjectBorrowerPlanDetail interestDetail = buildProjectBorrowerPlanDetail(snowflakeIdWorker.nextId(),
					project.getProjectId(), project.getBorrowUserId(), projectBorrowerPlanNew.getId(), FeeTypeEnum.INTEREST.getValue().intValue(), currentInterest);
			projectBorrowerPlanDetailMapperExt.insertSelective(interestDetail);

			projectBorrowerPlanNewList.add(projectBorrowerPlanNew);
		}

		result.setProjectBorrowerSummary(projectBorrowerSummary);
		result.setProjectBorrowerPlanNewList(projectBorrowerPlanNewList);
		return result;

	}

	@Override
	public List<ProjectInvestorPlan> buildInvestorRepaymentPlan(Project project,
			List<ProjectInvestOrder> projectInvestOrderList, BorrowerRepaymentDTO borrowerRepaymentDTO) {
		List<ProjectInvestorPlan> result = new ArrayList<ProjectInvestorPlan>();

		PeriodUnitEnum periodUnit = PeriodUnitEnum.enumOf(project.getDeadlineUnit());
		if (PeriodUnitEnum.MONTH != periodUnit) {
			Exceptions.throwBizException("TRD_700003");// 等额本息还款方式的期限单位不是月
		}

		// 月利率： 年化利率/12
		BigDecimal monthRate = project.getBorrowRate().divide(BigDecimal.valueOf(AmountHandleConstant.YEAR_OF_MONTH),
				MathContext.DECIMAL128);

		Map<Integer, BigDecimal> investCapitalTotal = new HashMap<>();
		Map<Integer, BigDecimal> investInterestTotal = new HashMap<>();

		List<ProjectBorrowerPlanNew> projectBorrowerPlanNewList = borrowerRepaymentDTO.getProjectBorrowerPlanNewList();

		boolean isPackagedProject = projectPackageLocalService.isPackagedProject(project.getProjectId());

		for (ProjectInvestOrder projectInvestOrder : projectInvestOrderList) {
			if (projectInvestOrder != null
					&& ProjectInvestOrderStatusEnum.SUCCESS.getValue().equals(projectInvestOrder.getStatus())) {

				Map<Integer, BigDecimal> capitalMap = getPerMonthCapital(projectInvestOrder.getAmount(), monthRate,
						project.getDeadline());
				Map<Integer, BigDecimal> interestMap = getPerMonthInterest(projectInvestOrder.getAmount(), monthRate,
						project.getDeadline());
				BigDecimal capitalTotal = BigDecimal.ZERO;

				Date firstReceivedDate = null;
				BigDecimal firstInterest = null;
				Date expectOverDate = null;
				BigDecimal investorInterest = BigDecimal.ZERO;

				for (ProjectBorrowerPlanNew projectBorrowerPlanNew : projectBorrowerPlanNewList) {
					ProjectInvestorPlan projectInvestorPlan = new ProjectInvestorPlan();
					projectInvestorPlan.setId(snowflakeIdWorker.nextId());
					projectInvestorPlan.setInvestOrderId(projectInvestOrder.getId());
					projectInvestorPlan.setInvestType(isPackagedProject ? Byte.valueOf("3") : Byte.valueOf("1"));
					projectInvestorPlan.setProjectId(projectInvestOrder.getProjectId());
					projectInvestorPlan.setOrgId(project.getOrgId());
					projectInvestorPlan.setUserId(projectInvestOrder.getUserId());
					projectInvestorPlan.setAccountId(projectInvestOrder.getAccountId());
					projectInvestorPlan.setPlatformUserNo(projectInvestOrder.getPlatformUserNo());
					projectInvestorPlan.setCurrentPeriod(projectBorrowerPlanNew.getPeriod());
					projectInvestorPlan.setTotalPeriod(projectBorrowerPlanNew.getTotalPeriod());
					projectInvestorPlan.setReceivedDate(projectBorrowerPlanNew.getRefundDate());
					projectInvestorPlan.setYearMouth(DateFormatUtils.format(projectBorrowerPlanNew.getRefundDate(), DatePatternConstant.YYYYMM));
					projectInvestorPlan.setPenaltyBeginDate(projectBorrowerPlanNew.getRefundDate());
					projectInvestorPlan.setReceivedStatus(InvestorPlanReceivedStatusEnum.NON_RECEIVE.getCode());
                    projectInvestorPlan.setInvestTime(projectInvestOrder.getCreateTime());
					projectInvestorPlan.setCreateTime(new Date());
					projectInvestorPlan.setUpdateTime(new Date());
					projectInvestorPlan.setCapital(capitalMap.get(projectBorrowerPlanNew.getPeriod()));
					projectInvestorPlan.setInterest(interestMap.get(projectBorrowerPlanNew.getPeriod()));
					capitalTotal = capitalTotal.add(projectInvestorPlan.getCapital());
					
					// 应还款本金不等于实际还款金额时 最后一期做本金抹平处理
					if (projectBorrowerPlanNew.getPeriod() == project.getDeadline()) {
						if (projectInvestOrder.getAmount().compareTo(capitalTotal) != 0) {
							projectInvestorPlan.setCapital(capitalMap.get(projectBorrowerPlanNew.getPeriod()).add(projectInvestOrder.getAmount().subtract(capitalTotal)));
							projectInvestorPlan.setInterest(interestMap.get(projectBorrowerPlanNew.getPeriod()).subtract(projectInvestOrder.getAmount().subtract(capitalTotal)));
						}
						
						if(projectInvestorPlan.getInterest().compareTo(BigDecimal.ZERO) < 0){
							projectInvestorPlan.setInterest(BigDecimal.ZERO);
						}
					} 
					
					projectInvestorPlanMapper.insertSelective(projectInvestorPlan);

					result.add(projectInvestorPlan);

					if (investCapitalTotal.get(projectBorrowerPlanNew.getPeriod()) == null) {
						investCapitalTotal.put(projectBorrowerPlanNew.getPeriod(), projectInvestorPlan.getCapital());
						investInterestTotal.put(projectBorrowerPlanNew.getPeriod(), projectInvestorPlan.getInterest());
					} else {
						investCapitalTotal.put(projectBorrowerPlanNew.getPeriod(), investCapitalTotal.get(projectBorrowerPlanNew.getPeriod()).add(projectInvestorPlan.getCapital()));
						investInterestTotal.put(projectBorrowerPlanNew.getPeriod(), investInterestTotal.get(projectBorrowerPlanNew.getPeriod()).add(projectInvestorPlan.getInterest()));
					}

					if (1 == projectInvestorPlan.getCurrentPeriod()) {
						firstReceivedDate = projectInvestorPlan.getReceivedDate();
						firstInterest = projectInvestorPlan.getInterest();
					}
					if (project.getDeadline() == projectInvestorPlan.getCurrentPeriod()) {
						expectOverDate = projectInvestorPlan.getReceivedDate();
					}
					investorInterest = investorInterest.add(projectInvestorPlan.getInterest());
				}

				InvestorCreditor investorCreditor = buildInvestorCreditor(snowflakeIdWorker.nextId(), project, projectInvestOrder, firstReceivedDate, firstInterest, expectOverDate, projectInvestOrder.getAmount(),investorInterest);
				investorCreditorMapperExt.insertSelective(investorCreditor);
			}
		}

		/**
		 * 更新借款人应还款本金为投资人应收款本金之和,应还款利息为投资人应收款利息之和
		 */
		updateBorrowerCapitalInterest(projectBorrowerPlanDetailMapperExt, investCapitalTotal, investInterestTotal, projectBorrowerPlanNewList);
		return result;
	}

	/**
	 * 等额本息计算每月偿还本金和利息
	 * <p>
	 * 公式：每月偿还本息=〔贷款本金×月利率×(1＋月利率)＾还款月数〕÷〔(1＋月利率)＾还款月数-1〕
	 *
	 * @param capital
	 *            本金
	 * @param monthRate
	 *            月利息
	 * @param totalPeriod
	 *            总期数
	 * @return
	 */
	private BigDecimal getPerMonthPrincipalInterest(BigDecimal capital, BigDecimal monthRate, int totalPeriod) {
		BigDecimal dividend = capital.multiply(monthRate.multiply(BigDecimal.ONE.add(monthRate).pow(totalPeriod)));
		BigDecimal divisor = (BigDecimal.ONE.add(monthRate)).pow(totalPeriod).subtract(BigDecimal.ONE);
		BigDecimal result = dividend.divide(divisor, AmountHandleConstant.CALCULATE_PRECISION_TWO,
				BigDecimal.ROUND_HALF_EVEN);
		return result;
	}
	
	/**
	 * 计算最后一期偿还本金和利息([不做保留两位的每月还款 乘以 总期数] 减去 [保留两位的每月还款 乘以 (总期数 -1)]) 最后保留两位
	 * @param capital
	 * @param monthRate
	 * @param totalPeriod
	 * @return
	 */
	private BigDecimal getLastPerMonthPrincipalInterest(BigDecimal capital, BigDecimal monthRate, int totalPeriod) {
		BigDecimal dividend = capital.multiply(monthRate.multiply(BigDecimal.ONE.add(monthRate).pow(totalPeriod)));
		BigDecimal divisor = (BigDecimal.ONE.add(monthRate)).pow(totalPeriod).subtract(BigDecimal.ONE);
		BigDecimal result = dividend.divide(divisor, MathContext.DECIMAL128);
		
		BigDecimal total = getPerMonthPrincipalInterest(capital, monthRate, totalPeriod).multiply(new BigDecimal(totalPeriod - 1)).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO,
				BigDecimal.ROUND_HALF_EVEN);
		result = result.multiply(new BigDecimal(totalPeriod)).subtract(total).setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO,
				BigDecimal.ROUND_HALF_EVEN);
		return result;
	}

	/**
	 * 等额本息计每月偿还利息
	 * <p>
	 * 公式：每月偿还利息=贷款本金×月利率×〔(1+月利率)^还款期数-(1+月利率)^(还款月序号-1)〕÷〔(1+月利率)^还款期数-1〕
	 *
	 * @param capital
	 *            总借款额（贷款本金）
	 * @param monthRate
	 *            月利率
	 * @param totalPeriod
	 *            总期数
	 * @return 每月偿还利息
	 */
	private Map<Integer, BigDecimal> getPerMonthInterest(BigDecimal capital, BigDecimal monthRate, int totalPeriod) {
		Map<Integer, BigDecimal> map = new HashMap<Integer, BigDecimal>();
		BigDecimal monthInterest;
		for (int i = 1; i < totalPeriod + 1; i++) {
			BigDecimal multiply = capital.multiply(monthRate);
			BigDecimal sub = (BigDecimal.ONE.add(monthRate).pow(totalPeriod)).subtract(BigDecimal.ONE.add(monthRate)
					.pow(i - 1));
			monthInterest = multiply.multiply(sub).divide(
					(BigDecimal.ONE.add(monthRate).pow(totalPeriod).subtract(BigDecimal.ONE)), MathContext.DECIMAL128);
			monthInterest = monthInterest.setScale(AmountHandleConstant.CALCULATE_PRECISION_TWO,
					BigDecimal.ROUND_HALF_EVEN);
			map.put(i, monthInterest);
		}
		return map;
	}

	/**
	 * 等额本息计算每月偿还本金
	 *
	 * @param capital
	 *            总借款额（贷款本金）
	 * @param monthRate
	 *            月利率
	 * @param totalPeriod
	 *            还款期数
	 * @return 每月偿还本金
	 */
	private Map<Integer, BigDecimal> getPerMonthCapital(BigDecimal capital, BigDecimal monthRate, int totalPeriod) {
		BigDecimal monthIncome = getPerMonthPrincipalInterest(capital, monthRate, totalPeriod);
		Map<Integer, BigDecimal> mapInterest = getPerMonthInterest(capital, monthRate, totalPeriod);

		Map<Integer, BigDecimal> mapPrincipal = new HashMap<Integer, BigDecimal>();
		for (Map.Entry<Integer, BigDecimal> entry : mapInterest.entrySet()) {
			if(entry.getKey() < mapInterest.entrySet().size()){
				mapPrincipal.put(entry.getKey(), monthIncome.subtract(entry.getValue()));
			} else {
				mapPrincipal.put(entry.getKey(),
						getLastPerMonthPrincipalInterest(capital, monthRate, totalPeriod).subtract(entry.getValue()));
			}
		}
		return mapPrincipal;
	}
	
}
